package io.terminus.lego.shinda.web.security

import io.terminus.lego.shinda.web.security.email.configure.EmailLoginConfigurer
import io.terminus.lego.shinda.web.security.email.filter.EmailCodeAuthenticationProcessingFilter
import io.terminus.lego.shinda.web.security.email.provider.EmailAuthenticationProvider
import io.terminus.lego.shinda.web.security.phone.filter.SMSCodeAuthenticationProcessingFilter
import io.terminus.lego.shinda.web.security.phone.provider.SmsAuthenticationProvider
import io.terminus.lego.shinda.web.security.service.UCOAuth2UserService
import io.terminus.lego.shinda.web.security.special_user.configure.SpecialUserLoginConfigurer
import io.terminus.lego.shinda.web.security.special_user.filter.SpecialUserAuthenticationProcessingFilter
import io.terminus.lego.shinda.web.security.special_user.provider.SpecialUserAuthenticationProvider
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.annotation.web.configurers.SmsLoginConfigurer
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.web.authentication.AuthenticationFailureHandler
import org.springframework.security.web.authentication.AuthenticationSuccessHandler
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler

/**
 * @author wangmeng
 * @date 2018/4/12
 */
@EnableWebSecurity
class SecurityConfig @Autowired constructor(val userDetailsService: UserDetailsService,
                                            val ucOAuth2UserService: UCOAuth2UserService,
                                            val successHandler: AuthenticationSuccessHandler,
                                            val failureHandler: AuthenticationFailureHandler,
                                            val smsAuthenticationProvider: SmsAuthenticationProvider,
                                            val emailAuthenticationProvider: EmailAuthenticationProvider,
                                            val specialUserAuthenticationProvider: SpecialUserAuthenticationProvider) : WebSecurityConfigurerAdapter() {
    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        val smsFilter = SMSCodeAuthenticationProcessingFilter()
        val emailFilter = EmailCodeAuthenticationProcessingFilter()
        val specialUserFilter = SpecialUserAuthenticationProcessingFilter()
        http
                .authorizeRequests()
                .antMatchers("/css/**", "/index", "/test/**", "/swagger**").permitAll()
                .antMatchers("/api/proxy/access-token/**").permitAll()
                .antMatchers("/user/**").hasRole("USER")
                .antMatchers("/").authenticated()
                .antMatchers("/api/index/**").authenticated()
                .antMatchers("/api/bind/**").authenticated()
                .antMatchers("/api/oauth/**").authenticated()
                .and()
                .authorizeRequests()
                .and()
                //form表单登录
                .formLogin()
                .loginProcessingUrl("/login")
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .and()
                .csrf().disable()
                .headers().frameOptions().disable()
                .and().logout()
                .logoutSuccessHandler(HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK))
                .invalidateHttpSession(true)
                .and()
                //第三方账户登录
                .oauth2Login()
//                .successHandler(successHandler)
                .userInfoEndpoint()
                .userService(ucOAuth2UserService)
                .and()
                .and()
                //短信登录
                .addFilterBefore(smsFilter, UsernamePasswordAuthenticationFilter::class.java)
                .apply(SmsLoginConfigurer<HttpSecurity>(smsFilter, smsAuthenticationProvider))
                .loginProcessingUrl("/login-phone")
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .and()
                //邮箱验证码登录
                .addFilterBefore(emailFilter, UsernamePasswordAuthenticationFilter::class.java)
                .apply(EmailLoginConfigurer<HttpSecurity>(emailFilter,emailAuthenticationProvider))
                .loginProcessingUrl("/login-email")
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .and()
                //特殊账户登录
                .addFilterBefore(specialUserFilter, UsernamePasswordAuthenticationFilter::class.java)
                .apply(SpecialUserLoginConfigurer<HttpSecurity>(specialUserFilter, specialUserAuthenticationProvider))
                .loginProcessingUrl("/login-special")
                .successHandler(successHandler)
                .failureHandler(failureHandler)
                .and()
                .rememberMe()
                .rememberMeCookieName("re-me")
    }

    @Autowired
    @Throws(Exception::class)
    fun configureGlobal(auth: AuthenticationManagerBuilder) {
        // ensure the passwords are encoded properly
        auth.userDetailsService(userDetailsService)

    }
}